package com.kxmall.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 地理编码工具类 - 通过地址获取经纬度
 * 
 * @author kxmall
 * @date 2025-08-31
 */
@Slf4j
@Component
public class GeocodingUtils {

    /**
     * 百度地图API密钥 - 需要在百度地图开放平台申请
     * 建议将此配置移到配置文件中
     */
    private static final String BAIDU_AK = "your_baidu_api_key";
    
    /**
     * 高德地图API密钥 - 需要在高德地图开放平台申请
     * 建议将此配置移到配置文件中
     */
    private static final String AMAP_KEY = "your_amap_api_key";

    /**
     * 地理编码结果类
     */
    public static class GeocodingResult {
        private BigDecimal longitude;
        private BigDecimal latitude;
        private boolean success;
        private String errorMessage;

        public GeocodingResult(BigDecimal longitude, BigDecimal latitude, boolean success, String errorMessage) {
            this.longitude = longitude;
            this.latitude = latitude;
            this.success = success;
            this.errorMessage = errorMessage;
        }

        // Getters
        public BigDecimal getLongitude() { return longitude; }
        public BigDecimal getLatitude() { return latitude; }
        public boolean isSuccess() { return success; }
        public String getErrorMessage() { return errorMessage; }
    }

    /**
     * 通过地址获取经纬度坐标
     * 优先使用高德地图API，失败后尝试百度地图API
     * 
     * @param province 省份
     * @param city 城市
     * @param county 区县
     * @param address 详细地址
     * @return 地理编码结果
     */
    public GeocodingResult getCoordinatesByAddress(String province, String city, String county, String address) {
        // 构建完整地址
        String fullAddress = buildFullAddress(province, city, county, address);
        
        log.info("开始地理编码，地址：{}", fullAddress);
        
        // 优先尝试高德地图API
        GeocodingResult result = getCoordinatesByAmap(fullAddress);
        if (result.isSuccess()) {
            log.info("高德地图地理编码成功，经度：{}，纬度：{}", result.getLongitude(), result.getLatitude());
            return result;
        }
        
        log.warn("高德地图地理编码失败：{}，尝试百度地图", result.getErrorMessage());
        
        // 尝试百度地图API
        result = getCoordinatesByBaidu(fullAddress);
        if (result.isSuccess()) {
            log.info("百度地图地理编码成功，经度：{}，纬度：{}", result.getLongitude(), result.getLatitude());
            return result;
        }
        
        log.error("所有地理编码服务都失败了，地址：{}", fullAddress);
        return new GeocodingResult(null, null, false, "地理编码失败：" + result.getErrorMessage());
    }

    /**
     * 构建完整地址字符串
     */
    private String buildFullAddress(String province, String city, String county, String address) {
        StringBuilder sb = new StringBuilder();
        if (province != null && !province.trim().isEmpty()) {
            sb.append(province.trim());
        }
        if (city != null && !city.trim().isEmpty()) {
            sb.append(city.trim());
        }
        if (county != null && !county.trim().isEmpty()) {
            sb.append(county.trim());
        }
        if (address != null && !address.trim().isEmpty()) {
            sb.append(address.trim());
        }
        return sb.toString();
    }

    /**
     * 使用高德地图API进行地理编码
     */
    private GeocodingResult getCoordinatesByAmap(String address) {
        try {
            String encodedAddress = URLEncoder.encode(address, StandardCharsets.UTF_8.toString());
            String urlStr = String.format("https://restapi.amap.com/v3/geocode/geo?key=%s&address=%s", 
                    AMAP_KEY, encodedAddress);
            
            String response = sendHttpRequest(urlStr);
            if (response == null) {
                return new GeocodingResult(null, null, false, "网络请求失败");
            }
            
            JSONObject jsonResponse = JSON.parseObject(response);
            String status = jsonResponse.getString("status");
            
            if (!"1".equals(status)) {
                return new GeocodingResult(null, null, false, "高德API返回错误：" + jsonResponse.getString("info"));
            }
            
            JSONArray geocodes = jsonResponse.getJSONArray("geocodes");
            if (geocodes == null || geocodes.isEmpty()) {
                return new GeocodingResult(null, null, false, "未找到匹配的地址");
            }
            
            JSONObject geocode = geocodes.getJSONObject(0);
            String location = geocode.getString("location");
            if (location == null || location.trim().isEmpty()) {
                return new GeocodingResult(null, null, false, "返回的坐标为空");
            }
            
            String[] coords = location.split(",");
            if (coords.length != 2) {
                return new GeocodingResult(null, null, false, "坐标格式错误");
            }
            
            BigDecimal longitude = new BigDecimal(coords[0]);
            BigDecimal latitude = new BigDecimal(coords[1]);
            
            return new GeocodingResult(longitude, latitude, true, null);
            
        } catch (Exception e) {
            log.error("高德地图地理编码异常", e);
            return new GeocodingResult(null, null, false, "高德地图API调用异常：" + e.getMessage());
        }
    }

    /**
     * 使用百度地图API进行地理编码
     */
    private GeocodingResult getCoordinatesByBaidu(String address) {
        try {
            String encodedAddress = URLEncoder.encode(address, StandardCharsets.UTF_8.toString());
            String urlStr = String.format("https://api.map.baidu.com/geocoding/v3/?address=%s&output=json&ak=%s", 
                    encodedAddress, BAIDU_AK);
            
            String response = sendHttpRequest(urlStr);
            if (response == null) {
                return new GeocodingResult(null, null, false, "网络请求失败");
            }
            
            JSONObject jsonResponse = JSON.parseObject(response);
            Integer status = jsonResponse.getInteger("status");
            
            if (status == null || status != 0) {
                return new GeocodingResult(null, null, false, "百度API返回错误，状态码：" + status);
            }
            
            JSONObject result = jsonResponse.getJSONObject("result");
            if (result == null) {
                return new GeocodingResult(null, null, false, "返回结果为空");
            }
            
            JSONObject location = result.getJSONObject("location");
            if (location == null) {
                return new GeocodingResult(null, null, false, "坐标信息为空");
            }
            
            BigDecimal longitude = location.getBigDecimal("lng");
            BigDecimal latitude = location.getBigDecimal("lat");
            
            if (longitude == null || latitude == null) {
                return new GeocodingResult(null, null, false, "坐标值为空");
            }
            
            return new GeocodingResult(longitude, latitude, true, null);
            
        } catch (Exception e) {
            log.error("百度地图地理编码异常", e);
            return new GeocodingResult(null, null, false, "百度地图API调用异常：" + e.getMessage());
        }
    }

    /**
     * 发送HTTP请求
     */
    private String sendHttpRequest(String urlStr) {
        try {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(10000);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");
            
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                log.error("HTTP请求失败，响应码：{}", responseCode);
                return null;
            }
            
            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            connection.disconnect();
            
            return response.toString();
            
        } catch (Exception e) {
            log.error("HTTP请求异常", e);
            return null;
        }
    }

    /**
     * 验证经纬度是否有效
     */
    public boolean isValidCoordinates(BigDecimal longitude, BigDecimal latitude) {
        if (longitude == null || latitude == null) {
            return false;
        }
        
        // 经度范围：-180 到 180
        // 纬度范围：-90 到 90
        return longitude.compareTo(new BigDecimal("-180")) >= 0 
                && longitude.compareTo(new BigDecimal("180")) <= 0
                && latitude.compareTo(new BigDecimal("-90")) >= 0 
                && latitude.compareTo(new BigDecimal("90")) <= 0;
    }
}
